package com.sunday.common.core.permissions;

import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 权限加密计算
 * @Author: zsy
 */
@Slf4j
public class PermissionsEncode {

    /**
     * 最大权限码 取整数60
     */
    private static final long MAX_CODE = 1L << 59;

    /**
     * 权限位二进制码生成一维数组
     *
     * @param list       集合
     * @param classifier 分组键
     * @param mapper     映射值
     * @return {@link long[]}
     * <p>
     * long[] sum = new long[1];
     * for (Permissions permissions : list) {
     * sum[permissions.getPosition()] |= permissions.getCode();
     * }
     * return sum;
     */
    public static <T> long[] generate(List<T> list, Function<T, Integer> classifier, Function<T, Long> mapper) {
        Map<Integer, Long> map = list.stream().collect(Collectors.groupingBy(classifier, Collectors.reducing(0L, mapper, (a, b) -> a | b)));
        long[] sum = new long[map.size()];
        map.forEach((position, codeSum) -> sum[position] = codeSum);
        return sum;
    }

    /**
     * @Description: 计算下一位 权限位 权限码
     * @Param: [position, code]
     * @Return: com.sunday.user.center.security.utils.PermissionsUtils.Result
     */
    public static Result next(int position, long code) {
        if (position < 0) {
            position = 0;
        }
        if (code < 1L) {
            code = 1L;
        } else {
            code <<= 1L;
        }
        if (code > MAX_CODE) {
            position += 1;
            code = 1L;
        }
        return Result.builder().position(position).code(code).build();
    }

    /**
     * @Description: 权限运算结果
     */
    @Data
    @Builder
    public static class Result {
        /**
         * 权限位
         */
        private int position;

        /**
         * 权限码
         */
        private long code;
    }

}
